import type { AxiosInstance } from 'axios'
import axios from 'axios'
import type { RequestConfig } from './type'

// 实际上，config的数据类型AxiosRequestConfig中并没有对应的数据类型，所以需要我们自行添加
// interface RequestConfig extends AxiosRequestConfig {
//   interceptors?: { // 此时我们就能够添加判断是否需要单独设置的拦截器的属性了
//     requestSuccessFn: (config: AxiosRequestConfig) => AxiosRequestConfig // 请求成功拦截
//     requestFailFn: (err: any) => any // 请求失败拦截
//     responseSuccessFn: (res: AxiosResponse) => AxiosResponse // 响应成功拦截
//     responseFailFn: (err: any) => any // 响应失败拦截
//   }
// }

class Request {
  instance: AxiosInstance

  constructor(config: RequestConfig) {
    this.instance = axios.create(config)

    // 每个instance添加拦截器，这里的拦截器都是全局的拦截器
    // 请求拦截器
    this.instance.interceptors.request.use(
      (config) => {
        // console.log('into request interceptors')

        return config
      },
      (err) => {
        // console.log('error request')
        return err
      }
    )

    // 响应拦截器
    this.instance.interceptors.response.use(
      (res) => {
        // console.log('into response interceptors')

        return res.data
      },
      (err) => {
        // console.log('error response')

        return err
      }
    )

    // 针对特定的Request实例添加拦截器
    if (config.interceptors) {
      this.instance.interceptors.request.use(
        config.interceptors.requestSuccessFn,
        config.interceptors.requestFailFn
      )
      this.instance.interceptors.response.use(
        config.interceptors.responseSuccessFn,
        config.interceptors.responseFailFn
      )
    }
  }

  // 封装网络请求的方法
  request<T = any>(config: RequestConfig) {
    if (config.interceptors?.requestSuccessFn) {
      config = config.interceptors.requestSuccessFn(config)
    }

    return new Promise<T>((resolve, reject) => {
      // 单次响应成功拦截处理
      this.instance
        .request<any, T>(config)
        .then((res) => {
          if (config.interceptors?.responseSuccessFn) {
            // @ts-ignore
            res = config.interceptors.responseSuccessFn(res)
          }

          resolve(res)
        })
        .catch((err) => {
          reject(err)
        })
    })
  }

  get<T = any>(config: RequestConfig) {
    return this.request({ ...config, method: 'GET' })
  }

  post(config: RequestConfig) {
    return this.request({ ...config, method: 'POST' })
  }

  delete(config: RequestConfig) {
    return this.request({ ...config, method: 'DELETE' })
  }

  patch(config: RequestConfig) {
    return this.request({ ...config, method: 'PATCH' })
  }
}

export default Request
